package io

import (
	"fmt"
	"net"
	"strconv"
	"time"
)

type TCPClient struct {
	net.Conn
	useAutoReconnect bool
	ip               string
	port             int
	connecting       bool
	timeOutMilsecond int
}

func (_this *TCPClient) IsConnecting() bool {
	return _this.connecting
}

func (_this *TCPClient) AutoReconnect(async bool) {
	reconnectFunc := func() {
		if _this.connecting {
			return
		}
		_this.connecting = true
		for i := 0; _this.connectInternal() != nil; i++ {
			fmt.Println("重连中..." + strconv.Itoa(i))
			if i < 3 {
				time.Sleep(time.Second * 3)
			} else if i < 5 {
				time.Sleep(time.Second * 15)
			} else if i < 10 {
				time.Sleep(time.Second * 30)
			} else if i < 50 {
				time.Sleep(time.Second * 60)
			} else {
				time.Sleep(time.Second * 60 * 3)
			}
		}
		_this.connecting = false
	}
	if async {
		go reconnectFunc()
	} else {
		reconnectFunc()
	}
}

func (_this *TCPClient) Connect() error {
	if _this.useAutoReconnect {
		_this.AutoReconnect(false)
		return nil
	}
	return _this.connectInternal()
}

func (_this *TCPClient) connectInternal() error {
	if _this.Conn != nil {
		_this.Conn.Close()
	}
	var err error
	_this.Conn, err = net.Dial("tcp", fmt.Sprintf("%s:%d", _this.ip, _this.port))
	if err != nil {
		return err
	}
	return nil
}

func (_this *TCPClient) Read() ([]byte, error) {
	if _this.timeOutMilsecond > 0 {
		_this.Conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(_this.timeOutMilsecond)))
	}
	buffer := make([]byte, 4096)
	len, err := _this.Conn.Read(buffer)
	if err != nil {
		if _this.useAutoReconnect {
			_this.AutoReconnect(false)
		}
		return nil, err
	}
	buffer = buffer[:len]
	return buffer, nil
}

func (_this *TCPClient) Write(buffer []byte) error {
	if _this.timeOutMilsecond > 0 {
		_this.Conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(_this.timeOutMilsecond)))
	}
	_, err := _this.Conn.Write(buffer)
	if err != nil && _this.useAutoReconnect {
		_this.AutoReconnect(false)
	}
	return err
}
